﻿using AutoMapper;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Mvc;
using Microsoft.Data.Entity;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.PlatformAbstractions;
using Sino.CapacityCloud.Infrastructure.Features;
using Sino.CapacityCloud.Repositories.Models;
using Sino.CapacityCloud.Services;
using Sino.CapacityCloud.WebApi.ViewModels;
using Sino.Tms.Primitives;
using Sino.Tms.WebApi.Framework.Primitives;
using Sino.WebApi.Framework.Core.Filters;
using Sino.WebApi.Framework.Responses;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Z.EntityFramework.Plus;

namespace Sino.CapacityCloud.WebApi.ApiControllers
{

    public partial class UserController
    {

        [SupressUserLogin]
        public async Task<JsonResult> SearchUsers(string keyword, int skip = 0, int count = 10)
        {
            try
            {
                IQueryable<ApplicationUser> list = this.DataContext.Users
                    .AsNoTracking()
                    .Include(x => x.Car)
                    .ThenInclude(x => x.AddingCommit)
                    .Include(x => x.CommonTransportLinkages)
                    .ThenInclude(x => x.TransportLinkage)
                    .Include(x => x.BankCards)
                    .ThenInclude(x => x.Bank)
                    .Where(x => x.CarId != null);

                if (!string.IsNullOrWhiteSpace(keyword))
                {
                    list = list.Where(x =>
                       x.PhoneNumber.Contains(keyword) ||
                       x.RealName.Contains(keyword) ||
                       x.Car.Code.Contains(keyword));
                }

                var total = list.Count();

                if (total > 0)
                {
                    var response = new UserListResponse()
                    {
                        List = list.Skip(skip).Take(count).AsEnumerable().Select(x => Mapper.Map(x, new UserDetails())).ToList(),
                        Total = total
                    };
                    return await this.PackageResultAsync(response);
                }
                return await this.PackageResultAsync(new UserListResponse());
            }
            catch (Exception ex)
            {
                this._logger.LogError($"Failed to find users that match the filters you given because: {ex.Message + Environment.NewLine + ex.StackTrace}");
                return await this.PackageResultAsync<UserListResponse>(ex);
            }
        }

        [SupressUserLogin]
        public async Task<JsonResult> GetUserDetailList(string ids, string orderby, int asc, string carcode, VehicleType cartype, CarLength carlength, string inputperson, string driver, string driverphone, CarriageType carriercategory, string routeKeyword, int isenabled, DateTime? startTime, DateTime? endTime, int skip = 0, int count = 10)
        {
            try
            {
                var id_list = ids?.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                IQueryable<ApplicationUser> list = this.DataContext.Users
                    .AsNoTracking()
                    .Include(x => x.Car)
                    .ThenInclude(x => x.AddingCommit)
                    .Include(x => x.BankCards)
                    .ThenInclude(x => x.Bank)
                    .Include(x => x.CommonTransportLinkages)
                    .ThenInclude(x => x.TransportLinkage)
                    .Where(x => x.CarId != null);

                if (ids != null && id_list?.Count() > 0)
                {
                    list = list.Where(x => id_list.Contains(x.Id));
                }
                if (!string.IsNullOrWhiteSpace(carcode))
                {
                    list = list.Where(x => x.Car.Code.Contains(carcode));
                }
                if (cartype != VehicleType.None)
                {
                    list = list.Where(x => x.Car.Type == cartype);
                }
                if (carlength != CarLength.None)
                {
                    list = list.Where(x => x.Car.Length == carlength);
                }
                if (carriercategory != CarriageType.None)
                {
                    list = list.Where(x => x.CarriageType == carriercategory);
                }
                // 1：true，2：false，0：Null
                switch (isenabled)
                {
                    case 2:
                        list = list.Where(x => (!x.LockoutEnabled) == false);
                        break;
                    case 1:
                        list = list.Where(x => (!x.LockoutEnabled) == true);
                        break;
                    case 0:
                    default:
                        break;
                }
                if (startTime != null)
                {
                    list = list.Where(x => x.Car.Date >= startTime);
                }
                if (endTime != null)
                {
                    list = list.Where(x => x.Car.Date < endTime);
                }
                if (!string.IsNullOrWhiteSpace(driverphone))
                {
                    list = list.Where(x => x.PhoneNumber.Contains(driverphone));
                }
                if (!string.IsNullOrWhiteSpace(driver))
                {
                    list = list.Where(x => x.RealName.Contains(driver));
                }

                if (!string.IsNullOrWhiteSpace(inputperson) || !string.IsNullOrWhiteSpace(routeKeyword))
                {
                    list = list.ToList().AsQueryable();
                    if (!string.IsNullOrWhiteSpace(inputperson))
                    {
                        //list = list.Where(x => x.Car.AddingCommit.Committer.Contains(inputperson));
                        list = list.Where(x => SystemUtils.Try(() => x.Car.AddingCommit.Committer.Contains(inputperson), false));
                    }
                    if (!string.IsNullOrWhiteSpace(routeKeyword))
                    {
                        //list = list.Where(x => x.CommonTransportLinkages
                        //        .Any(z => z.TransportLinkage.StartingPlaceName.Contains(routeKeyword) ||
                        //            z.TransportLinkage.DestinationPlaceName.Contains(routeKeyword)));
                        list = list.Where(x => SystemUtils.Try(() => x.CommonTransportLinkages
                                .Any(z => z.TransportLinkage.StartingPlaceName.Contains(routeKeyword) ||
                                    z.TransportLinkage.DestinationPlaceName.Contains(routeKeyword)), false));
                    }
                }

                if (!string.IsNullOrEmpty(orderby))
                {
                    var isAcs = asc != 1;
                    switch (orderby)
                    {
                        case "carcode":
                            if (isAcs)
                                list = list.OrderBy(x => x.Car.Code);
                            else
                                list = list.OrderByDescending(x => x.Car.Code);
                            break;
                        case "cartype":
                            if (isAcs)
                                list = list.OrderBy(x => x.Car.Type);
                            else
                                list = list.OrderByDescending(x => x.Car.Type);
                            break;
                        case "carlength":
                            if (isAcs)
                                list = list.OrderBy(x => x.Car.Length);
                            else
                                list = list.OrderByDescending(x => x.Car.Length);
                            break;
                        case "inputperson":
                            if (isAcs)
                                list = list.OrderBy(x => x.Car.AddingCommit.Committer);
                            else
                                list = list.OrderByDescending(x => x.Car.AddingCommit.Committer);
                            break;
                        case "driver":
                            if (isAcs)
                                list = list.OrderBy(x => x.RealName);
                            else
                                list = list.OrderByDescending(x => x.RealName);
                            break;
                        case "driverphone":
                            if (isAcs)
                                list = list.OrderBy(x => x.PhoneNumber);
                            else
                                list = list.OrderByDescending(x => x.PhoneNumber);
                            break;
                        case "carriercategory":
                            if (isAcs)
                                list = list.OrderBy(x => x.CarriageType);
                            else
                                list = list.OrderByDescending(x => x.CarriageType);
                            break;
                        case "isenabled":
                            if (isAcs)
                                list = list.OrderBy(x => x.LockoutEnabled);
                            else
                                list = list.OrderByDescending(x => x.LockoutEnabled);
                            break;
                        default:
                            break;
                    }
                }

                var total = list.Count();

                if (total > 0)
                {
                    list = list.Skip(skip);
                    if (count > 0)
                    {
                        list = list.Take(count);
                    }
                    var response = new UserListResponse()
                    {
                        List = list.AsEnumerable()
                            .Select(x => Mapper.Map(x, new UserDetails()))
                            .ToList(),
                        Total = total
                    };
                    return await this.PackageResultAsync(response);
                }
                return await this.PackageResultAsync(new UserListResponse());
            }
            catch (Exception ex)
            {
                this._logger.LogError($"Failed to find users that match the filters you given because: {ex.Message + Environment.NewLine + ex.StackTrace}");
                return await this.PackageResultAsync<UserListResponse>(ex);
            }
        }
    }

}